﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace AsyncServer_1
{
    public class Serv
    {
        // 监听的socket
        public Socket listenfd;

        // 客户端连接
        public Conn[] conns;

        public const int MaxConn = 50; // 最大连接数


        /// <summary>
        /// 获取连接池索引,返回负数表示获取失败
        /// </summary>
        /// <returns></returns>
        private int NewIndex() { 
            for(int i = 0; i < conns.Length; ++i)
            {
                if (!conns[i].bInUse)
                {
                    return i;
                }
            }
            return -1;
        }

        /// <summary>
        /// 开启服务器
        /// </summary>
        public void Start(string host,int port) {

            // 初始化连接池
            conns = new Conn[MaxConn];
            for(int i = 0; i < MaxConn; ++i)
            {
                conns[i] = new Conn();
            }

            listenfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            // bind
            IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(host), port);
            listenfd.Bind(endPoint);

            // listen
            listenfd.Listen(MaxConn);

            // accept
            listenfd.BeginAccept(AcceptCb, null);
            Console.WriteLine("[服务器]  启动成功!");
        }

        private void AcceptCb(IAsyncResult ar)
        {
            try
            {
                Socket socket = listenfd.EndAccept(ar);
                int index = NewIndex();
                if (index < 0)
                {
                    socket.Close();
                    Console.WriteLine("[警告] 连接已满!");
                    return;
                }

                Conn conn = conns[index];
                conn.Init(socket);
                string addr = conn.GetAddress();
                Console.WriteLine($"客户端连接 [{addr}], conn池 id:{index}");
                conn.socket.BeginReceive(conn.readBuffer, conn.bufferCount, conn.BuffRemain(), SocketFlags.None, ReceiveCb, conn);
            }
            catch(Exception e)
            {
                Console.WriteLine(e);
                Console.WriteLine("AcceptCb Error!");
            }

            //  实现循环监听...
            listenfd.BeginAccept(AcceptCb, null);
        }

        private void ReceiveCb(IAsyncResult ar) {
            Conn conn = (Conn)ar.AsyncState;


            try
            {
                int count = conn.socket.EndReceive(ar);

                // 关闭信号
                if (count <= 0)
                {
                    Console.WriteLine($"收到 [{conn.GetAddress() }] 断开连接");
                    conn.Close();
                    return;
                }

                // 数据处理
                string str = Encoding.UTF8.GetString(conn.readBuffer,0, count);
                Console.WriteLine($"收到 [{conn.GetAddress()}] 数据:{str}");

                // 广播出去
                byte[] bytes = Encoding.UTF8.GetBytes(str);
                for (int i = 0; i < conns.Length; ++i)
                {
                    if (conns[i].bInUse)
                    {
                        conns[i].socket.Send(bytes);
                    }
                }

                //  继续接收
                conn.socket.BeginReceive(conn.readBuffer, conn.bufferCount, conn.BuffRemain(), SocketFlags.None, ReceiveCb, conn);
            }catch(Exception e)
            {
                Console.WriteLine(e);
                Console.WriteLine($"收到 [{conn.GetAddress()}] 断开连接!");
                conn.Close();
            }
        }
    }
}
